﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Data;
using Microsoft.Practices.Prism.ViewModel;
using Microsoft.Practices.Prism.Commands;
using System.ComponentModel;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Microsoft.Win32;
using System.Windows;

namespace ZSens.ViewModel
{
    class MainWindowViewModel:NotificationObject
    {
        private bool isBegin;

        public bool IsBegin
        {
            get { return isBegin; }
            set { 
                isBegin = value;
                this.RaisePropertyChanged("IsBegin");
            }
        }
        private List<System.Windows.Controls.Button> buttons;
        private BindingList<Layout> layouts;

        public BindingList<Layout> Layouts
        {
            get { return layouts; }
            set {
                    layouts = value;
                    this.RaisePropertyChanged("Layouts");
            }
        }
        private Layout currentLayout;

        public Layout CurrentLayout
        {
            get { return currentLayout; }
            set { 
                currentLayout = value;
                this.RaisePropertyChanged("CurrentLayout");
            }
        }
        

        private BindingList<Player> players;
        private int current;

        public int Current
        {
            get { return current; }
            set
            {
                current = value;
                this.RaisePropertyChanged("Current");
            }
        }
        
        private int currentLayer;

	    public int CurrentLayer
	    {
		    get { return currentLayer;}
		    set { 
                currentLayer = value;
                this.RaisePropertyChanged("CurrentLayer");
            }
	    }
	
        private Player curPlayer;

        public Player CurPlayer
        {
            get { return curPlayer; }
            set { 
                curPlayer = value;
                this.RaisePropertyChanged("CurPlayer");
            }
        }

        public BindingList<Player> Players
        {
            get { return players; }
            set {
                players = value;
                this.RaisePropertyChanged("Players");
            }
        }

        public string GetBeginString()
        {
            if (IsBegin)
                return "Stop";
            else
                return "Begin";
        }
        private MainWindow owner;
        public void AddPlayer(Player player)
        {
            players.Add(player);
            Current = players.Count - 1;
        }

        public void RemovePlayer(Player player)
        {
            players.Remove(player);
        }

        public DelegateCommand ConfigOrientationCommand { get; set; }
        public DelegateCommand<Widget> ConfigButtonCommand { get; set; }
        public DelegateCommand SelectPlayerCommand { get; set; }
        public DelegateCommand SelectLayoutsCommand { get; set ;}
        public DelegateCommand BeginGameCommand { get; set; }
        public DelegateCommand ApplyLayoutCommand { get; set; }
        public DelegateCommand RemovePlayerCommand { get; set; }
        public DelegateCommand SaveLayoutCommand { get; set; }
        public DelegateCommand LoadLayoutCommand { get; set; }
        public DelegateCommand RemoveLayoutCommand { get; set; }
        public MainWindowViewModel(MainWindow window)
        {
            owner = window;
            isBegin = true;
            players = new BindingList<Player>();
            layouts = new BindingList<Layout>();
            buttons = new List<System.Windows.Controls.Button>();
            layouts.Add(new BallanceLayout());
            layouts.Add(new NeedForSpeedLayout());
            this.ConfigButtonCommand = new DelegateCommand<Widget>(new System.Action<Widget>(this.ConfigButtonCommandExecute));
            this.ConfigOrientationCommand = new DelegateCommand(new System.Action(this.ConfigOrientationCommandExecute));
            this.SelectPlayerCommand = new DelegateCommand(new System.Action(this.SelectPlayerCommandExecute));
            this.SelectLayoutsCommand = new DelegateCommand(new System.Action(this.SelectLayoutsCommandExecute));
            this.BeginGameCommand = new DelegateCommand(new System.Action(this.BeginGameCommandExecute));
            this.ApplyLayoutCommand = new DelegateCommand(new System.Action(this.ApplyLayoutCommandExecute));
            this.RemovePlayerCommand = new DelegateCommand(new System.Action(this.RemovePlayerCommandExecute));
            this.SaveLayoutCommand = new DelegateCommand(new System.Action(this.SaveLayoutCommandExecute));
            this.LoadLayoutCommand = new DelegateCommand(new System.Action(this.LoadLayoutCommandExecute));
            this.RemoveLayoutCommand = new DelegateCommand(new System.Action(this.RemoveLayoutCommandExecute));
        }

        private void RemoveLayoutCommandExecute()
        {
            if (CurrentLayer >= 0)
            {
                this.layouts.RemoveAt(currentLayer);
            }
        }

        private void LoadLayoutCommandExecute()
        {
            OpenFileDialog openFileDialog = new OpenFileDialog();
            openFileDialog.Filter = "Layout files (*.zlayout)|*.zlayout|All files (*.*)|*.*";
            openFileDialog.FilterIndex = 1;
            openFileDialog.RestoreDirectory = true;
            Nullable<bool> ret = openFileDialog.ShowDialog();
            if (ret == true)
            {
                try
                {
                    System.IO.Stream stream = openFileDialog.OpenFile();
                    if (stream != null)
                    {
                        using (stream)
                        {
                            int length = (int)stream.Length;
                            byte[] bLayout = new byte[length];
                            stream.Read(bLayout, 0, length);
                            UnicodeEncoding uniEncoding = new UnicodeEncoding();
                            String strLayout = uniEncoding.GetString(bLayout);
                            JObject jLayout = JsonConvert.DeserializeObject<JObject>(strLayout);
                            Layout layout = new Layout();
                            layout.jDeserialize(jLayout);
                            layouts.Add(layout);
                        }
                    }
                }
                catch (Exception e)
                {
                    MessageBox.Show("Error: Could not read file from disk. Original error: " + e.Message);
                }
            }
        }

        private void SaveLayoutCommandExecute()
        {
            if (CurrentLayout == null)
            {
                System.Windows.MessageBox.Show("Layout not selected");
            }
            else
            {
                JObject jLayout = CurrentLayout.jSerialize();
                String strLayout = JsonConvert.SerializeObject(jLayout);
                SaveFileDialog saveFileDialog = new SaveFileDialog();
                saveFileDialog.Filter = "Layout files (*.zlayout)|*.zlayout|All files (*.*)|*.*";
                saveFileDialog.Title = "Save your layout";
                saveFileDialog.DefaultExt = "zlayout";
                UnicodeEncoding uniEncoding = new UnicodeEncoding();
                int length = uniEncoding.GetByteCount(strLayout);

                if (saveFileDialog.ShowDialog() == true && saveFileDialog.FileName != "")
                {
                    System.IO.FileStream fs = (System.IO.FileStream)saveFileDialog.OpenFile();
                    fs.Write(uniEncoding.GetBytes(strLayout), 0, length);
                    fs.Close();
                }
            }
        }

        private void RemovePlayerCommandExecute()
        {
            if (Current >= 0 && players.Count != 0)
            {
                Player player = players[Current];
                lock (player.lockDisconnect)
                {
                    if (player.status == Player.Running)
                    {
                        players.RemoveAt(Current);
                        CurrentLayout = null;
                        CurrentLayer = -1;
                        player.status = Player.Recycling;
                    }
                }
            }
        }

        private void ApplyLayoutCommandExecute()
        {
            if (Current >= 0 && players.Count != 0)
            {
                Player player = players[Current];
                if (CurrentLayout == null)
                    return;
                lock (player.lockDisconnect)
                {
                    if (player.status == Player.Constructing)
                    {
                        player.layout = CurrentLayout.Clone() as Layout;
                        player.status = Player.Pending;
                    }
                    else if (player.status == Player.Running)
                    {
                        MainWindow.getInstance().StopVMultiUpdate();
                        VMultiAPI.VMulti.GetInstance().Reset();
                        player.layout = CurrentLayout.Clone() as Layout;
                        player.status = Player.Pending;
                        MainWindow.getInstance().StartVMultiUpdate();
                    }
                }
            }
        }

        public void ConfigButtonCommandExecute(Widget o) {
            if (o is Button)
            {
                new ConfigButton((Button)o).Show();
            }
            else if (o is Orientation)
            {
                new ConfigOrientation((Orientation)o).Show();
            }
        }

        public void ConfigOrientationCommandExecute()
        {

        }

        public void BeginGameCommandExecute()
        {
            if (IsBegin)
            {
                IsBegin = false;
            }
            else
            {
                IsBegin = true;
            }
        }

        public void SelectPlayerCommandExecute()
        {
            if (Current >= 0)
            {
                CurPlayer = players[Current];
                CurrentLayer = -1;
                foreach (System.Windows.Controls.Button item in buttons)
                {
                    owner.Container.Children.Remove(item);
                }
                if (CurPlayer.layout != null)
                {
                    CurrentLayout = CurPlayer.layout.Clone() as Layout;
                    GenerateButtons();
                    foreach (System.Windows.Controls.Button item in buttons)
                    {
                        owner.Container.Children.Add(item);
                    }
                    for (int i = 0; i < layouts.Count; i++)
                    {
                        //shouldn't check using string ANYMORE!!!
                        if (layouts[i].DisplayString == CurrentLayout.DisplayString)
                            CurrentLayer = i;
                    }
                }
                else
                    CurrentLayout = null;
            }
        }
        public void SelectLayoutsCommandExecute()
        {
            if (CurrentLayer >= 0)
            {
                foreach (System.Windows.Controls.Button item in buttons)
                {
                    owner.Container.Children.Remove(item);
                }
                CurrentLayout = layouts[CurrentLayer].Clone() as Layout;
                GenerateButtons();
                foreach (System.Windows.Controls.Button item in buttons)
                {
                    owner.Container.Children.Add(item);
                }
            }
        }

        private void GenerateButtons()
        {
            buttons.Clear();
            foreach (var item in CurrentLayout.widgets)
            {
                System.Windows.Controls.Button btn = null;
                if (item is OrientationX)
                {
                    btn = CreateButton(owner.X.Margin.Left,owner.X.Margin.Top,0,0, owner.X.Height, owner.X.Width, true);
                }

                if (item is OrientationY)
                {
                    btn = CreateButton(owner.Y.Margin.Left,owner.Y.Margin.Top,0,0, owner.Y.Height, owner.Y.Width, true);
                }

                if (item is Button)
                {
                    double left = (item as Button).leftUP.X / 100;
                    double top = (item as Button).leftUP.Y / 100;
                    double width = ((item as Button).rightDown.X - (item as Button).leftUP.X) / 100;
                    double height = ((item as Button).rightDown.Y - (item as Button).leftUP.Y) / 100;
                    btn = CreateButton(left, top, 0, 0, height, width, false);
                    btn.SizeChanged += btn_SizeChanged;
                }
                SetBind(btn, item);
                buttons.Add(btn);
            }
        }

        void btn_SizeChanged(object sender, SizeChangedEventArgs e)
        {
            return;
        }
        public System.Windows.Controls.Button CreateButton(double left, double top, double right, double bottom, double height, double width, bool isOrientation)
        {
            System.Windows.Controls.Button btn = new System.Windows.Controls.Button();
            btn.HorizontalAlignment = System.Windows.HorizontalAlignment.Left;
            btn.VerticalAlignment = System.Windows.VerticalAlignment.Top;
            System.Windows.Controls.TextBlock block = new System.Windows.Controls.TextBlock();
            block.TextWrapping = System.Windows.TextWrapping.Wrap;
            block.TextAlignment = System.Windows.TextAlignment.Center;
            btn.Content = block;
            if (isOrientation)
            {
                btn.Margin = new System.Windows.Thickness(left, top, right, bottom);
                btn.Height = height;
                btn.Width = width;
            }
            else
            {
                
                btn.Margin = new System.Windows.Thickness(left * owner.CellPhone.ActualWidth + owner.CellPhone.Margin.Left,
                                                            top * owner.CellPhone.ActualHeight + owner.CellPhone.Margin.Top,
                                                            right, bottom);
                btn.Height = height * owner.CellPhone.ActualHeight;
                btn.Width = width * owner.CellPhone.ActualWidth;
                
            }
            return btn;
        }

        public void SetBind(System.Windows.Controls.Button btn, Widget w)
        {
            Binding bind = new Binding();
            w.DisplayString = w.GetDisplayString();
            btn.Command = ConfigButtonCommand;
            btn.CommandParameter = w;
            bind.Source = w;
            bind.Path = new System.Windows.PropertyPath("DisplayString");
            bind.NotifyOnSourceUpdated = true;
            ((System.Windows.Controls.TextBlock)(btn.Content)).SetBinding(System.Windows.Controls.TextBlock.TextProperty, bind);
        }
    }
}
